/**
 * @class ICTouchAPI.KeyboardTypes
 * @singleton
 * @extends Object
 * Keyboard types
 *
 * <pre><code>
 * Keyboard Types
 * - "ALPHANUM"
 * - "NUM"
 * - "FILTER"
 * - "DIALPAD"
 * - "EMOTICON"
 * - "PASSWORD"
 * - "NUMSEARCH"
 * - "ALPHASEARCH"
 * - "DTMF"
 * </code></pre>
 */
ICTouchAPI.KeyboardTypes = {

    /**
     * @cfg {String} ALPHANUM Standard alpha numeric
     * @ignore
     */
    ALPHANUM: "alphaNum",

    /**
     * @cfg {String} NUM Standard numeric
     * @ignore
     */
    NUM: "num",

    /**
     * @cfg {String} FILTER Filtered
     * @ignore
     */
    FILTER: "filter",

    /**
     * @cfg {String} DIALPAD Dialpad without additional button
     * @ignore
     */
    DIALPAD: "dialpad",

    /**
     * @cfg {String} EMOTICON Emoticon buttons
     * @ignore
     */
    EMOTICON: "emoticons",

    /**
     * @cfg {String} PASSWORD Standard alpha numeric with password
     * @ignore
     */
    PASSWORD: "password",

    /**
     * @cfg {String} NUMSEARCH Dialpad with additional button to switch to alphaNum search
     * @ignore
     */
    NUMSEARCH: "numSearch",

    /**
     * @cfg {String} ALPHASEARCH Standard alpha numeric with additional button to switch to dialpad
     * @ignore
     */
    ALPHASEARCH: "alphaSearch",

    /**
     * @cfg {String} DTMF Dialpad with only a cancel button
     * @ignore
     */
    DTMF: "dtmf",

    /**
     * @cfg {String} NUMMDRS Dialpad with additional button for Multi Device Routing Selection
     * @ignore
     */
    NUMMDRS: "numMultiDevice",

    /**
     * @cfg {String} PASSWORD Standard numeric with password
     * @ignore
     */
    NUMPASSWORD: "numPassword"
}


/**
 * @class ICTouchAPI.KeyboardAlphanumMode
 * @singleton
 * @extends Object
 * Alphanumerique Keyboard Modes
 *
 * <pre><code>
 * Alphanumerique Keyboard Modes
 * - "NORMAL"
 * - "CAPS"
 * - "CAPS_LOCK"
 * - "NUMERIC"
 * </code></pre>
 */
ICTouchAPI.KeyboardAlphanumMode = {
    /**
     * @cfg {String} NORMAL Normal keyboard mode
     * @ignore
     */
    NORMAL: "normal",
    /**
     * @cfg {String} CAPS Non locked Caps keyboard mode
     * @ignore
     */
    CAPS: "caps",
    /**
     * @cfg {String} CAPS_LOCK Locked Caps keyboard mode
     */
    CAPS_LOCK: "capsLock",
    /**
     * @cfg {String} NUMERIC Numeric keyboard mode
     * @ignore
     */
    NUMERIC: "numeric"
}


/**
 * @class ICTouchAPI.keyboardServices
 * @singleton
 * @extends Object
 * Keyboard management
 */
dojo.provide("ICTouchAPI.keyboardServices");
dojo.declare("ICTouchAPI.keyboardServices", null,
    {
        // Attributes.
        // Current keyboard.
        _objCurrentKeyboard: {},
        // Current characters sequence to build a candidate.
        _charSequence: "",
        // InputField that deployed the keyboard.
        _objCalledBy: {},
        // Initial caret position (absolute) when starting a charSequence.
        _initialCaretPos: 0,
        // Current caret position (absolute)
        _currentCaretPos: 0,
        // IF current language requires an IME.
        _IMERequired: false,
        // Loaded keyboards (1 for each keyboard type).
        _arrKeyboards: {},
        // A callback function if value is not to be returned in an inputField, like "make call"
        _funcCallbackOk: null,
        // A callback function called when the keyboard is closed (CLOSE_ACTION_EXIT or cancel if _funcCallbackManualExit is not defined).
        _funcCallbackExit: null,
        // A callback function called when the "Exit" key is pressed.
        _funcCallbackManualExit: null,
        // A callback function called when a key is pressed.
        _funcCallbackKeyPress: null,
        // A callback function called when a key is pressed.
        _funcCallbackKeyPressed: null,
        // A callback function called when a key is released.
        _funcCallbackKeyReleased: null,
        // Array of custom callbacks (they are created by webapps and accessed through UI Keyboard)
        _arrCustomCallbacks: [],
        // Set this to true to autoClose previous keyboard when opening a new one.
        autoClose: true,
        value: "",
        numPadLengthLimit: -1,
        // Popup for keyboard switch
        keyboardPopup: null,
        // List of the different keyboard
        sltList: null,
        //Calling webapp
        callingWebapp: null,

        // Constants used for function closeKeyboard
        CLOSE_ACTION_NONE: -1,
        CLOSE_ACTION_EXIT: 0,
        CLOSE_ACTION_OK: 1,
        CLOSE_ACTION_MANUAL_EXIT: 2,

        /* Relation between a complex keyboard type "ICTouchAPI.KeyboardTypes" and an UI keyboard type with corresponding flags
         There is also the function _setConditionalFlags that sets some flags
         */
        _keyboardTypeMapping: {
            "alphaNum": {
                "simpleType": "alphaNum"
            },
            "num": {
                "simpleType": "num",
                'international': false,
                "dialSpace": false
            },
            "filter": {
                "simpleType": "alphaNum",
                "filter": true
            },
            "dialpad": {
                "simpleType": "num",
                'international': true,
                "dialSpace": true
                // Also got conditional flags
            },
            "emoticons": {
                "simpleType": "alphaNum",
                "emoticon": true
            },
            "password": {
                "simpleType": "alphaNum",
                "password": true
            },
            "numSearch": {
                "simpleType": "num",
                'international': true,
                "dialSpace": false
                // Also got conditional flags
            },
            "alphaSearch": {
                "simpleType": "alphaNum",
                "byDialpad": true
                // Also got conditional flags
            },
            "dtmf": {
                "simpleType": "num",
                "ok": false,
                "backspace": false,
                "dialSpace": false
                //Hi Soft
            }
        },
        //Hi Soft
        imeLangSwitcher: {
            lastIME: "pinyin",
            switchIME: {
                "chinese": {
                    lang: ['apac_en', 'pinyin']
                },

                "japanese": {
                    lang: ['apac_en', 'Katakana', 'Hiragana']
                },

                "korean": {
                    lang: ['apac_en', 'Hangul']
                }
            }
        },
        arrayUnique: function (array) {
            var key, output, value, _i, _ref, _results;
            output = {};
            for (key = _i = 0, _ref = array.length; 0 <= _ref ? _i < _ref : _i > _ref; key = 0 <= _ref ? ++_i : --_i) {
                output[array[key]] = array[key];
            }
            _results = [];
            for (key in output) {
                value = output[key];
                _results.push(value);
            }
            return _results;
        },
        _getAPACIMELangs: function () {
            var tempObject = this.imeLangSwitcher.switchIME;
            var tempArr = [];
            for (var item in tempObject) {
                var obj = tempObject[item];
                if (obj.hasOwnProperty("lang")) {
                    tempArr = tempArr.concat(obj.lang);
                }
            }
            return  this.arrayUnique(tempArr);
        },

        apacIMELangs: null,
        "numMultiDevice": {
            "simpleType": "num",
            "latest": true
        },
        "numPassword": {
            "simpleType": "num",
            "password": true
        },

        arrEmoIcon: null,
        arrEmoIconConvert: [],

        _hotelMode: false,
        _multiDeviceRoutingMode: false,
        _actionButtonInDialpad: 0,
        _arrDialpadKeys: [],
        _arrRegisteredKeys: [],
        _arrProgKeys: [],
        _arrProgKeysLocalisation: [],
        _customKeysUpdated: false,

        //Hi Soft
        getLastLang: function () {
            return this.imeLangSwitcher.lastIME;
        },
        getNextLang: function (strLang) {
            return 'apac_en' == strLang ? this.imeLangSwitcher.lastIME : (this.imeLangSwitcher.lastIME = strLang, "apac_en");
        },


        /**
         * @ignore
         */
        constructor: function () {
            // Sets a flag if an IME is required.
            this._IMERequired = false;
            //Hi Soft
            this.apacIMELangs = this._getAPACIMELangs();

            var strPath = "library/ICTouchAPI/UIElements/Keyboard/themes/Default/images/";
            var that = this;
            dojo.xhrGet({
                url: "library/ICTouchAPI/UIElements/Keyboard/keyMaps/emoticon.json",
                handleAs: "json",
                sync: true,

                load: function (response) {
                    that.arrEmoIcon = response.arrEmoIcon;

                },

                error: function (response, ioArgs) {
                    console.error(ioArgs);
                }
            });
            //console.log(that.arrEmoIcon);
            for (var i in this.arrEmoIcon) {
                if (this.arrEmoIcon) {
                    this.arrEmoIcon[i][0] = strPath + this.arrEmoIcon[i][0] + "_normal_24.png";
                    if (this.arrEmoIcon[i][1]) {
                        var reg = RegExp("m-e");
                        this.arrEmoIcon[i][0] = this.arrEmoIcon[i][0].replace(reg, "m_e");
                        this.arrEmoIconConvert.push(this.arrEmoIcon[i]);
                    }
                }
            }
            dojo.subscribe("ModeHotel", this, this._hotelModeReceveid);


            dojo.subscribe("ModeMultiDeviceRouting", this, this._multiDeviceRoutingRecieved);

            dojo.subscribe("HomepageRegisterKey", this, this.registerDialpadKey);

            dojo.subscribe("HomepageUnregisterKey", this, this.unregisterDialpadKey);
        },

        /**
         * Get the keyboard's inputField value
         * @return {string} inputField's value
         */
        getValue: function () {
            return this._objCurrentKeyboard.getInputField().getInputFieldContent();
        },

        /**
         * Get the name of the group the field belongs to, if any.
         * @return {String} the group name, or false
         * @ignore
         */
        getFieldGroupName: function () {
            if (this._objCalledBy) {
                return this._objCalledBy.linkedFields;
            } else {
                return false;
            }
        },

        /**
         * Get current deployed keyboard
         * @return {Object} current keyboard
         */
        getCurrentKeyboard: function () {
            // WRK crms00199760
            return this._objCurrentKeyboard;
        },

        /**
         * @ignore
         */
        getApplicationName: function () {
            return "keyboardServices";
        },

        /**
         * @ignore
         */
        _getSimpleKeyboardType: function (type) {
            var keyboardType = this._keyboardTypeMapping[type];
            if (!keyboardType) {
                ICTouchAPI.debugServices.debug("Unknown keyboard type: " + type, false);
                return null;
            }
            return this._keyboardTypeMapping[type].simpleType;
        },

        /**
         * Regain focus of keyboard's input field.
         * When a key is pressed, the focus is lost, then its content scrolls back to the beginning
         * of the input field.
         * @ignore
         */
        focusInputField: function () {
            this._objCurrentKeyboard.getInputField().getInputFieldObject().focus();
        },

        /**
         * Get InputField of current keyboard
         * @return {Object} Current InputField
         */
        getInputField: function () {
            return this._objCurrentKeyboard.getInputField();
        },

        /**
         * One of the two inputs of this service. This input might trigger a candidate collection from the IME.
         * @param {String} UTF8char the "keyed in" character (virtual or physical keyboard)
         * @ignore
         */
        keyPressed: function (UTF8char) {
            if (this.numPadLengthLimit != -1 && this._objCurrentKeyboard.getInputField().getInputFieldContent().length >= this.numPadLengthLimit) {
                return;
            }
            // WRK crms00199717
            if (UTF8char === "&amp;") {
                UTF8char = "&";
            }
            // WRK crms00199518
            else if (UTF8char === "&lt;") {
                UTF8char = "<";
            }
            else if (UTF8char === "&gt;") {
                UTF8char = ">";
            }

            var caretPos = this._objCurrentKeyboard.getInputField().getCaretPos();

            if ((this._currentCaretPos > caretPos) ||
                (caretPos > (this._initialCaretPos + this._charSequence.length))) {
                // If caretPos got out of previous charSquence, reset everything.
            }
            // Save current caret position.
            this._currentCaretPos = caretPos;

            if (this._funcCallbackKeyPress) {
                this._funcCallbackKeyPress(UTF8char);
            }

            // If IME is required,
            if (this._IMERequired) {
                // If it's a new char sequence
                if (ICTouchAPI.IMEServices.getCharSequenceLength() === 0) {
                    // Save current caret position as the start of the new char sequence.
                    // This will be used to know where to start replacing the sequence by the selected candidate.
                    this._initialCaretPos = this._currentCaretPos;
                }
                ICTouchAPI.IMEServices.keyPressed(UTF8char);
            } else {
                this.displayChar(UTF8char, false);
            }
        },

       /**
        * Display a string in IME input zone
        * */
        displayIMEString: function (UTF8String){
           this._objCurrentKeyboard.setIMEString(UTF8String);
        },

        /**
         * @ignore
         */
        displayChar: function (UTF8char, boolOnIMEInput) {
            if (boolOnIMEInput) {
                this._objCurrentKeyboard.addIMEChar(UTF8char)
                return;
            } else {
                this._objCurrentKeyboard.getInputField().addNewChar(UTF8char);
                if (this._funcCallbackKeyPressed) {
                    this._funcCallbackKeyPressed(this._objCurrentKeyboard.getInputField().getInputFieldContent());
                }
            }
        },

        /**
         * @ignore
         */
        replaceChar: function (UTF8Char, boolOnIMEInput) {
            //Hi Soft
            this._objCurrentKeyboard.deleteIMEChar();
            this.displayChar(UTF8Char, boolOnIMEInput);
            //Hi Soft
        },
        //Hi Soft
        pushInputIntoField: function (clearInputZone) {
            this._objCurrentKeyboard.pushInputZoneIntoInputField(clearInputZone);
        },

        displayCharInInputField: function (ch) {
            this._objCurrentKeyboard.displayCharInInputField(ch, true);
        },

        /**
         * @ignore
         */
        displayCandidates: function (arrCandidates) {
            this._objCurrentKeyboard.recreateCandidateList(arrCandidates);
        },

        /**
         * @ignore
         */
        setIMERequirement: function (boolIMERequired) {
            this._IMERequired = boolIMERequired;
        },

        /**
         * @ignore
         */
        keyReleased: function (UTF8char) {
            if (this._funcCallbackKeyReleased) {
                this._funcCallbackKeyReleased(UTF8char);
            }
        },

        /**
         * @ignore
         */
        delChars: function (boolOnIMEInput) {
            //Hi Soft
            if (boolOnIMEInput && this._objCurrentKeyboard.deleteIMEChar()) {
                ICTouchAPI.IMEServices.delChar();
                return;
                //Hi Soft
            }
            this._objCurrentKeyboard.getInputField().delChars();
            if (this._funcCallbackKeyPressed) {
                this._funcCallbackKeyPressed(this._objCurrentKeyboard.getInputField().getInputFieldContent());
                //Hi Soft
                //}
            }
        },

        /**
         * Close the keyboard.
         * @param {Number} intAction action triggered: 0 = Exit, 1 = Ok, -1 = none
         */
        closeKeyboard: function (intAction) {
            ICTouchAPI.toasterServices.hideContent(this._objCurrentKeyboard);
            if (!this._objCurrentKeyboard.closed) {
                this._objCurrentKeyboard.closed = true;
                if (intAction == this.CLOSE_ACTION_OK) {
                    if (this._objCalledBy) {
                        this.sendInputFieldContent();
                    } else if (this._funcCallbackOk) {
                        this._funcCallbackOk(this.getValue());
                    }
                }
                else if (intAction == this.CLOSE_ACTION_MANUAL_EXIT && this._funcCallbackManualExit) {
                    this._funcCallbackManualExit();
                }
                else if ((intAction == this.CLOSE_ACTION_EXIT || intAction == this.CLOSE_ACTION_MANUAL_EXIT) && this._funcCallbackExit) {
                    this._funcCallbackExit();
                }
            } else {
                ICTouchAPI.debugServices.warning("ICTouchAPI.keyboardServices - closeKeyboard / keyboard already closed... No action triggered.");
            }
            //this._objCurrentKeyboard.domNode.style.display = 'none';
        },

        /**
         * @ignore
         */
        sendInputFieldContent: function () {
            this._objCalledBy.setInputFieldContent(this._objCurrentKeyboard.getInputField().getInputFieldContent());
        },

        /**
         * The second input of this service. Allows for direct input of candidates.
         * Ends with a call to the virtual keyboard that will replace the char sequence by the candidate.
         * @param {String} UTF8char is the selected candidate.
         * @ignore
         */
        candidateSelected: function (UTF8char) {
            ICTouchAPI.IMEServices.candidateSelected(UTF8char);
        },

        /**
         * Deploys or not a keyboard according to target's version (MR/VHE)
         * @param {String} type is the type of the keyboard (num, alphanum...)
         * @param {Object} objCallingInputField is the inputField that fired up the keyboard.
         * @param {Object} objCustomParams contains custom parameters used if no input field was defined.
         *    It can contain
         * <pre><code>
         * - {String} strDefaultText a text to be displayed in the keyboard's inputField when open
         * - {Boolean} bMultiLines specifies if caller is multiLines (so will be the keyboard's inputfield)
         * - {String}  strDefaultMode initial mode for alphanumeric keyboard (ICTouchAPI.KeyboardAlphanumMode enumeration) (default: NORMAL)
         * - {Boolean} showVoicemailButton hide or show the voicemail button
         * - {Boolean} showAddcontactButton hide or show the AddContact button
         * - {Boolean} hideStarsIfPasswordEmpty hide or not the stars displayed in the input field when the content is a password
         * - {Function} funcCallbackOk the OK callback
         * - {Function} funcCallbackExit the EXIT callback
         * - {Function} funcCallbackKeyPress the callback when a key is pressed (called before the character sequence is modified)
         * - {Function} funcCallbackKeyPressed the callback when a key is pressed (called after the character sequence is modified ; receives the character sequence in parameter)
         * - {Function} funcCallbackKeyReleased the callback when a key is released
         * - {Array} arrCustomCallbacks custom set of callbacks handled according to Keyboard type (see UIElement Keyboard)
         * </code></pre>
         */
        deployKeyboard: function (type, objCallingInputField, objCustomParams) {
            // If autoClose is set to true, then close the previous keyboard.
            if (this.autoClose === true && this._objCurrentKeyboard.domNode) {
                if (ICTouchAPI.toasterServices.isContentDisplayed(this._objCurrentKeyboard)) {
                    this.closeKeyboard(ICTouchAPI.keyboardServices.CLOSE_ACTION_NONE);
                }
            }
            var _str, _numLockKeyboard;
            var multiline = false;
            this.numPadLengthLimit = -1;
            var keyboardType = this._getSimpleKeyboardType(type);
            if (!keyboardType) {
                return;
            }

            objCustomParams = objCustomParams || {};
            //add the possibility to define its own strings and icon for OK and EXIT
            var okLabel = objCustomParams.strOkLabel || null;
            var okIcon = objCustomParams.strOkIcon || null;
            var exitLabel = objCustomParams.strExitLabel || null;
            var exitIcon = objCustomParams.strExitIcon || null;
            if (objCustomParams.callingWebapp) {
                this.callingWebapp = objCustomParams.callingWebapp;
            } else {
                this.callingWebapp = null;
            }
            // If keyboard type is numeric we override the labels
            if (keyboardType === "num") {
                okLabel = _("", "ICTouchAPI");
                if (type === ICTouchAPI.KeyboardTypes.NUMSEARCH || type === ICTouchAPI.KeyboardTypes.DIALPAD) {
                    exitLabel = _("Cancel", "ICTouchAPI");
                    exitIcon = "generic-cancel";
                }
            }

            // Set the callback function and reset any previous save of the caller's inputfield
            this._funcCallbackOk = ICTouchAPI.tools.callbackToHitch(objCustomParams.funcCallbackOk);
            this._funcCallbackExit = ICTouchAPI.tools.callbackToHitch(objCustomParams.funcCallbackExit);
            this._funcCallbackManualExit = ICTouchAPI.tools.callbackToHitch(objCustomParams.funcCallbackManualExit);

            if (objCallingInputField) {
                this._funcCallbackKeyPress = null;
                this._funcCallbackKeyPressed = null;
                // WRK : crms00204576
                this._funcCallbackKeyReleased = null;
                this._arrCustomCallbacks = [];
                this._objCalledBy = objCallingInputField;
                _str = objCallingInputField.getInputFieldContent() || objCustomParams.strDefaultText || "";
                multiline = objCallingInputField.getMultiline();
                if (objCallingInputField.numLockKeyboard) {
                    _numLockKeyboard = objCallingInputField.numLockKeyboard;
                }
                else {
                    _numLockKeyboard = 0;
                }
            } else {
                // Set the callback function and reset any previous save of the caller's inputfield
                this._funcCallbackKeyPress = ICTouchAPI.tools.callbackToHitch(objCustomParams.funcCallbackKeyPress);
                this._funcCallbackKeyPressed = ICTouchAPI.tools.callbackToHitch(objCustomParams.funcCallbackKeyPressed);
                // WRK : crms00204576
                this._funcCallbackKeyReleased = ICTouchAPI.tools.callbackToHitch(objCustomParams.funcCallbackKeyReleased);
                if (objCustomParams.arrCustomCallbacks) {
                    this._arrCustomCallbacks = objCustomParams.arrCustomCallbacks;
                }
                this.numPadLengthLimit = objCustomParams.numPadLengthLimit;
                this._objCalledBy = null;
                multiline = objCustomParams.multiline;
                _str = objCustomParams.strDefaultText || "";
                if (_numLockKeyboard == undefined)
                    _numLockKeyboard = 0;
            }

            // Get the flags for this type of keyboard
            var keyboardFlags = this._keyboardTypeMapping[type];
            this._setConditionalFlags(keyboardFlags, type);
            // prevent the custom keys if it's a transfer
            if (objCustomParams && objCustomParams.strOkIcon && objCustomParams.strOkIcon.search("communication-deflect") != -1) {
                keyboardFlags.customKeys = false;
            }
            // Set multiline flag
            keyboardFlags['multiline'] = multiline;

            if (!this._arrKeyboards[keyboardType]) {
                this._arrKeyboards[keyboardType] = new UIElements.Keyboard.KeyboardControl({
                    strType: keyboardType,
                    strInputText: _str,
                    strInputTitle: objCustomParams.strInputTitle ? objCustomParams.strInputTitle : null,
                    numLockKeyboard: _numLockKeyboard,
                    hideStarsIfPasswordEmpty: objCustomParams.hideStarsIfPasswordEmpty,
                    strDefaultMode: objCustomParams.strDefaultMode,
                    "keyboardFlags": keyboardFlags
                });
            } else {
                var title = objCustomParams.strInputTitle ? objCustomParams.strInputTitle : "";
                // Flags should be changed before anything else. Because we need the buttons to update their labels
                this._arrKeyboards[keyboardType].setTitle(title);
                this._arrKeyboards[keyboardType].setKeyboardFlags(keyboardFlags);
                this._arrKeyboards[keyboardType].setMode(objCustomParams.strDefaultMode);
                // Set keyboard's input field to caller's value.
                this._arrKeyboards[keyboardType].getInputField().setInputFieldContent(_str, false, objCustomParams.hideStarsIfPasswordEmpty);
                this._arrKeyboards[keyboardType].numLockKeyboard = _numLockKeyboard;
                this._arrKeyboards[keyboardType].refreshFlags();
                this._arrKeyboards[keyboardType]._updateButtonsIcons();
            }

            this._objCurrentKeyboard = this._arrKeyboards[keyboardType];
            //signal the other webapps that a keyboard is displayed on screen
            this._objCurrentKeyboard.closed = false;
            // Joel: need to swap key map after deploying keyboard, else it won't be updated according to its flags
            this._objCurrentKeyboard._swapKeyMap();
            this._objCurrentKeyboard.updateOkExitButtonLabels(okLabel, exitLabel);
            this._objCurrentKeyboard.updateOkExitButtonIcons(okIcon, exitIcon);
            dojo.publish("keyboardServices.deployKeyboard", [true]);

            //ICTouchAPI.toasterServices.showContent(this._objCurrentKeyboard);
            //Hi Soft
            var isAPACIMELang = ICTouchAPI.keyboardServices.isAPACIMELang(this._objCurrentKeyboard.strLang);
            this.setIMERequirement(keyboardType == ICTouchAPI.KeyboardTypes.ALPHANUM && isAPACIMELang && !keyboardFlags.password);
            // update currentKeyboard Indicator
            if (keyboardType === ICTouchAPI.KeyboardTypes.ALPHANUM) {
                //update indicator when not password mode.
                this._objCurrentKeyboard._isPasswordKeyBoard = keyboardFlags.password;
                if (keyboardFlags.password && 'Hangul' == this._objCurrentKeyboard.strLang) this.switchKeyboardFromIMEIndicator("apac_en");
                this._objCurrentKeyboard.updateIMEIndicator();
                if(this._objCurrentKeyboard.strLang == "cyrillic_russian") this._objCurrentKeyboard._replaceButton(1,true,this._objCurrentKeyboard.convertToKeyboardLetter);
                this._objCurrentKeyboard.clearIMEInput();
            }
            var actionOutsideClick = objCustomParams.actionOutsideClick ? objCustomParams.actionOutsideClick : ICTouchAPI.keyboardServices.CLOSE_ACTION_EXIT;
            ICTouchAPI.toasterServices.showContent({
                "toasterContent": this._objCurrentKeyboard,
                "onOutsideClick": {context: this, func: function () {
                    this.closeKeyboard(actionOutsideClick)
                }}
            });

            // Put the focus on the InputField inside Keyboard
            this._objCurrentKeyboard.focus();
            type = null;
            objCallingInputField = null;
            objCustomParams = null;
        },

        /**
         * Preload a keyboard so the first load is faster
         * @param {String} type is the type of the keyboard (num, alphanum...)
         */
        preloadKeyboard: function (type) {
            var keyboardType = this._getSimpleKeyboardType(type);
            if (!keyboardType) {
                return;
            }
            if (!this._arrKeyboards[keyboardType]) {
                // Create minimal keyboard
                var keyboard = new UIElements.Keyboard.KeyboardControl({
                    strType: keyboardType,
                    strInputText: ""
                });
                this._arrKeyboards[keyboardType] = keyboard;
                ICTouchAPI.toasterServices.preloadContent(keyboard);
            }
        },

        /**
         * Is a keyboard displayed
         * @return {Boolean} true if a keyboard is displayed, false otherwise
         */
        isKeyboardDisplayed: function () {
            if (this._objCurrentKeyboard != null && this._objCurrentKeyboard.id != null) {
                return ICTouchAPI.toasterServices.isContentDisplayed(this._objCurrentKeyboard);
            }
            else {
                return false;
            }
        },

        /**
         * @ignore
         */
        doCustomCallback: function (strId, args) {
            if (this._arrCustomCallbacks && this._arrCustomCallbacks[strId]) {
                this._arrCustomCallbacks[strId](args);
            }
            switch (strId) {
                case "voicemail":
                    if (webapp.communication) {
                        webapp.communication.data._boolDialKeyEntered = false;
                        webapp.communication.voiceMailBtnCallback();
                    }
                    this.closeKeyboard(this.CLOSE_ACTION_EXIT);
                    break;
                case "goto-communication":
                    if (webapp.history) {
                        webapp.history.onHistoryEnter();
                    }
                    this.closeKeyboard(this.CLOSE_ACTION_EXIT);
                    break;
                case "goto-progkeys":
                    if (webapp.contacts) {
                        webapp.contacts.onFavoritesEnter();
                    }
                    this.closeKeyboard(this.CLOSE_ACTION_EXIT);
                    break;
                case "goto-contact":
                    if (webapp.contacts) {
                        webapp.contacts.onContactsEnter();
                    }
                    this.closeKeyboard(this.CLOSE_ACTION_EXIT);
                    break;
                case "show-latest":
                    if (webapp.userservices) {
                        webapp.userservices.displayCacheNumbersPopup();
                    }
                    break;
            }
        },
        //Hi Soft
        switchKeyboard: function () {
            ICTouchAPI.settingServices.getSetting("Defaultkeyboard", this, this._switchKeyboard);
        },

        /**
         * @ignore
         */
        //Hi Soft
        switchKeyboardFromIMEIndicator: function (strLang) {
            ICTouchAPI.settingServices.getSetting("Defaultkeyboard", this, function (objSetting) {
                var keyboardID = null;
                for (var i in objSetting.allowedValues) {
                    if (objSetting.allowedValues[i].name == strLang) {
                        keyboardID = objSetting.allowedValues[i].id;
                        break;
                    }
                }
                if (keyboardID != null) {
//                    console.log('keyboardID = ', keyboardID);
                    ICTouchAPI.settingServices.setSettingValue("Defaultkeyboard", keyboardID);
                } else {
                    console.warn("String language %s not found in settings.", strLang);
                }
            });
        },
        isAPACIMELang: function (strLang) {
            return this.apacIMELangs.some(function (elem) {
                return elem == strLang
            });
        },

        /**
         * @ignore
         */
        _switchKeyboard: function (objSetting) {
            var arrKeyboard = [];
            var context = this;
            for (var i in objSetting.allowedValues) {
                if (objSetting.allowedValues[i].name == 'apac_en') continue;
                var listItem = {};
                if (objSetting.allowedValues[i].id == objSetting.jsValue) {
                    listItem.boolSelected = true;
                } else {
                    listItem.boolSelected = false;
                }
                listItem.strLabel = _(objSetting.allowedValues[i].name, "UIElements.Keyboard")
                listItem.intIndex = i;
                listItem.itemCallback = dojo.hitch(this, this.updateKeyboard);
                arrKeyboard.push(listItem);
            }

            this.keyboardPopup = ICTouchAPI.popupServices.addNewPopup({
                strTitle: _("Keyboard", "UIElements.Keyboard"),
                arrPopupButtons: [
                    //Hi Soft
                    {
                        strButtonName: "Keyboard_popup_ok",
                        strButtonLabel: _("Ok", "ICTouchAPI"),
                        strButtonIcon: "generic-ok",
                        callback: function () {
                            context.updateKeyboard();
                        }
                    }
                ]
            }, "LOW");
            this.sltList = new UIElements.SelectList.SelectListControl({
                arrItems: arrKeyboard,
                boolMultiselect: false
            });
            var objPopup = ICTouchAPI.popupServices.getPopup(this.keyboardPopup.priority, this.keyboardPopup.position);
            objPopup.placeContent(this.sltList);

            objPopup.show();
        },

        /**
         * @ignore
         */
        _setConditionalFlags: function (keyboardFlags, type) {
            if (this._hotelMode) {
                keyboardFlags.hotelMode = true;
            }
            else {
                keyboardFlags.hotelMode = false;
            }
            switch (type) {
                case ICTouchAPI.KeyboardTypes.NUMSEARCH:
                    // set visibility of right button
                    keyboardFlags.gotoCommunication = false;
                    keyboardFlags.dialByName = false;
                    keyboardFlags.gotoContact = false;
                    keyboardFlags.gotoProgkeys = false;
                    keyboardFlags.gotoDirectory = false;
                    keyboardFlags.customKeys = false;
                    keyboardFlags.customKeysUpdated = false;
                    if (this._multiDeviceRoutingMode) {
                        if (this.callingWebapp == "userservices") {
                            keyboardFlags.latest = false;
                            if (typeof webapp.userservices !== "undefined") {
                                keyboardFlags.latest = 1;
                            }
                        } else {
                            keyboardFlags.latest = true;
                        }
                    }
                    if (!this._hotelMode) {
                        if (typeof webapp.search !== "undefined") {
                            keyboardFlags.dialByName = 1;
                        }
                        if (typeof webapp.contacts !== "undefined") {
                            keyboardFlags.gotoContact = 2;
                        }
                        if (typeof webapp.communication !== "undefined") {
                            keyboardFlags.gotoCommunication = 3;
                        }
                        if (typeof webapp.contacts !== "undefined") {
                            keyboardFlags.gotoProgkeys = 5;
                        }
                    }
                    else {
                        // if we are in hotel mode, custom keys must be displayed in dialpad
                        if (this._customKeysUpdated) {
                            this._customKeysUpdated = false;
                            keyboardFlags.customKeysUpdated = true;
                        }
                        keyboardFlags.customKeys = true;
                        keyboardFlags.actionButtonInDialpad = this._actionButtonInDialpad;
                    }
                    break;

            }
        },


        /**
         * @ignore
         */
        updateKeyboard: function () {
            var keyboardID = this.sltList.getSelected()[0];

            ICTouchAPI.popupServices.removePopup(this.keyboardPopup);
            ICTouchAPI.settingServices.setSettingValue("Defaultkeyboard", keyboardID);
            //Hi Soft
            console.log('keyboardID=', keyboardID);
            //this.closeKeyboard(this.CLOSE_ACTION_EXIT);
        },

        /**
         * @ignore
         * Guess the current webapp name
         */
        _getCurrentWebappName: function () {
            var name = ICTouchAPI.transitionServices.getCurrentScreenName();
            // Special case here, search webapp is a stealth one but we still want to display it in keyboard
            if (name !== "webapp.search.getSearch") {
                var name = ICTouchAPI.transitionServices.getCurrentScreenName(true);
            }
            if (typeof name == "string") {
                var webapp = name.split('.')[1];
                name = webapp ? webapp : "homepage";
            }
            else {
                name = "homepage";
            }
            return name;
        },


        /**
         * @ignore
         * Callback of hotel mode subscribe
         */
        _hotelModeReceveid: function () {
            this._hotelMode = true;
            // Default settings for simulation mode
            if (!generalConfig.simulation) {
                ICTouchAPI.settingServices.getSetting("ActionButtonInDialpad", this, this._actionButtonInDialpadReceived);
                ICTouchAPI.settingServices.subscribeToSetting(this, "ActionButtonInDialpad", this._actionButtonInDialpadReceived);
                ICTouchAPI.settingServices.getSetting("DialpadKeys", this, this._arrDialpadKeysReceivedFirst);
                ICTouchAPI.settingServices.subscribeToSetting(this, "DialpadKeys", this._arrDialpadKeysReceived);
            }
        },

        /**
         * @ignore
         * Callback of multi device rout
         */
        _multiDeviceRoutingRecieved: function () {
            this._multiDeviceRoutingMode = true;
        },

        /**
         * @ignore
         * Callback of ActionuttonInDialpad setting
         */
        _actionButtonInDialpadReceived: function (actionButtonInDialpad) {
            if (actionButtonInDialpad && actionButtonInDialpad.jsValue != undefined && actionButtonInDialpad.jsValue != null) {
                this._actionButtonInDialpad = actionButtonInDialpad.jsValue;
                this._customKeysUpdated = true;
            }
        },

        /**
         * @ignore
         * Callback of DialpadKeys setting (first time)
         */
        _arrDialpadKeysReceivedFirst: function (dialpadKeys) {
            this._arrDialpadKeysReceived(dialpadKeys);
            if (dialpadKeys && dialpadKeys.jsValue != undefined && dialpadKeys.jsValue != null) {
                ICTouchAPI.settingServices.getSettingValue("HomepageProgKeysLocalisation", this, this.loadedProgKeysLocalisationFirst);
                ICTouchAPI.settingServices.subscribeToSetting(this, "HomepageProgKeysLocalisation", this.loadedProgKeysLocalisation);
            }
        },

        /**
         * @ignore
         * Callback of DialpadKeys setting
         */
        _arrDialpadKeysReceived: function (dialpadKeys) {
            try {
                if (dialpadKeys && dialpadKeys.jsValue != undefined && dialpadKeys.jsValue != null) {
                    this._arrDialpadKeys = dialpadKeys.jsValue;
                    this._customKeysUpdated = true;
                }
            } catch (err) {
                ICTouchAPI.debugServices.debug(err.description, false);
            }
        },

        getDialpadKeys: function () {
            return this._arrDialpadKeys;
        },

        /**
         * @ignore
         * Callback of HomepageRegisterKey event
         */
        registerDialpadKey: function (strWebapp, strButtonName, strButtonIcon, strLabel, strStatusIcon, callBack, position, callbackLong) {
            var button = {};
            button = {
                strButtonName: strButtonName,
                strButtonLabel: strLabel,
                callback: function () {
                    callBack();
                    ICTouchAPI.keyboardServices.closeKeyboard(ICTouchAPI.keyboardServices.CLOSE_ACTION_EXIT);
                },
                strButtonIcon: strButtonIcon
            };
            this._arrRegisteredKeys.push(button);
            this._customKeysUpdated = true;
        },

        unregisterDialpadKey: function (strButtonName, boolForceDeleteKey) {
            for (var i = 0; i < this._arrRegisteredKeys.length; i++) {
                if (this._arrRegisteredKeys[i].strButtonName === strButtonName) {
                    this._arrRegisteredKeys.splice(i, 1);
                    break;
                }
            }
            this._customKeysUpdated = true;
        },

        /**
         * @ignore
         * Callback of HomepageProgKeysLocalisation setting (fist time)
         */
        loadedProgKeysLocalisationFirst: function (value) {
            this.loadedProgKeysLocalisation(value);
            ICTouchAPI.settingServices.getSetting("HomepageProgKeys", this, this.loadedProgKeysList);
            ICTouchAPI.settingServices.subscribeToSetting(this, "HomepageProgKeys", this.loadedProgKeysList);
        },

        /**
         * @ignore
         * Callback of HomepageProgKeysLocalisation setting
         */
        loadedProgKeysLocalisation: function (value) {
            try {
                if (value) {
                    this._arrProgKeysLocalisation = dojo.fromJson(value);
                }
            } catch (err) {
                ICTouchAPI.debugServices.debug(err.description, false);
            }
        },

        /**
         * @ignore
         * Callback of HomepageProgKeys setting
         */
        loadedProgKeysList: function (arrProgKeys) {
            var _arrProgKeys = [];
            try {
                if (arrProgKeys && arrProgKeys.jsValue != undefined && arrProgKeys.jsValue != null) {
                    _arrProgKeys = dojo.fromJson(arrProgKeys.jsValue);
                }
            } catch (err) {
                ICTouchAPI.debugServices.debug(err.description, false);
            }
            this._arrProgKeys = [];
            for (var i = 0; i < _arrProgKeys.length; i++) {
                if (_arrProgKeys[i] !== null && _arrProgKeys[i] !== undefined && _arrProgKeys[i] != "") {
                    var button = {
                        strButtonName: _arrProgKeys[i].id,
                        strButtonLabel: this.getKeyDMLabel(_arrProgKeys[i].label),
                        strCustomClass: (_arrProgKeys[i].webAppName == "communication" && _arrProgKeys[i].action == "call" ? 'call' : ''),
                        callback: function () {
                            ICTouchAPI.keyboardServices.closeKeyboard(ICTouchAPI.keyboardServices.CLOSE_ACTION_EXIT);
                        },
                        strButtonIcon: _arrProgKeys[i].icon
                    };
                    // another closure to prevent the variable key to be overwritten in each iteration of the loop
                    (function (key) {
                        button.callback = function () {
                            webapp[key.webAppName].onProgKeyClick(key);
                        };
                    })(_arrProgKeys[i]);
                    if (!button.strButtonLabel.isI18Ned) {
                        button.strLabelId = button.strButtonLabel;
                    }
                    this._arrProgKeys.push(button);
                }
            }
            this._customKeysUpdated = true;
        },

        /**
         * Get dialpad key from key id
         */
        getCustomKey: function (strButtonName) {
            if (strButtonName) {
                for (var i = 0; i < this._arrRegisteredKeys.length; i++) {
                    if (this._arrRegisteredKeys[i].strButtonName === strButtonName) {
                        return this._arrRegisteredKeys[i];
                    }
                }
                for (var j = 0; j < this._arrProgKeys.length; j++) {
                    if (this._arrProgKeys[j].strButtonName === strButtonName) {
                        return this._arrProgKeys[j];
                    }
                }
            }
            return null;
        },

        /**
         * Get Dialpad custom key label translation
         */
        getKeyDMLabel: function (strLabel) {
            var strLabelId = "";
            // if the object is already i18ned, return it
            if (strLabel.isI18Ned) {
                strLabelId = strLabel;
            }
            else if (this._arrProgKeysLocalisation && this._arrProgKeysLocalisation["en"] && this._arrProgKeysLocalisation["en"][strLabel]) {
                strLabelId = this._arrProgKeysLocalisation["en"][strLabel];
            }
            else {
                strLabelId = _(strLabel, "webapp.homepage");
            }
            return strLabelId;
        }




    });

ICTouchAPI.keyboardServices = new ICTouchAPI.keyboardServices();
